﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using UserSurface;
using ApplicationCore;

namespace EnzymeLaborTool
{
    public partial class FreshWeightCtrl : UserControl
    {
        public FreshWeightCtrl()
        {
            InitializeComponent();

        }

        private MainSurface _surface;
        private EnzymeDBDataContext _dataContext;

        private bool _initialized = false;
        public void Init(MainSurface ms)
        {
            if (!_initialized)
            {
                _surface = ms;
                InitDataContext();
                _initialized = true;
            }
        }

        public void Activate()
        {
            int fresWPosition = freshWeightViewBindingSource.Position;
            var freshSortCol = freshWeightDataGridView.SortedColumn;
            var freshSortOrder = freshWeightDataGridView.SortOrder;
            _invalidateFreshWeigthViewContext = true;
            BindFreshweights();
            if (freshSortCol != null)
            {
                switch (freshSortOrder)
                {
                    case SortOrder.Ascending:
                        {
                            freshWeightDataGridView.Sort(freshSortCol, ListSortDirection.Ascending);
                            break;
                        }

                    case SortOrder.Descending:
                        {
                            freshWeightDataGridView.Sort(freshSortCol, ListSortDirection.Descending);
                            break;
                        }
                    default:
                        break;
                }
            }
            if (fresWPosition > -1)
                freshWeightViewBindingSource.Position = fresWPosition;
        }

        private void InitDataContext()
        {
            //save sorting and position
            //int expPosition = experimentViewBindingSource.Position;

            //var expSortCol = experimentDataGridView.SortedColumn;
            //var expSortOrder = experimentDataGridView.SortOrder;

            //re-init datacontext
            _dataContext = _surface.CurrentDataContext;
            ApplyExperimentSecurity();
            ApplyFreshWeightSecurity();
            BindMaterial();
            BindExperiment();
            ApplyExperimentSecurity();
            ApplyFreshWeightSecurity();


            //restore sorting and positon
            //if (expSortCol != null)
            //{
            //    switch (expSortOrder)
            //    {
            //        case SortOrder.Ascending:
            //            {
            //                experimentDataGridView.Sort(expSortCol, ListSortDirection.Ascending);
            //                break;
            //            }

            //        case SortOrder.Descending:
            //            {
            //                experimentDataGridView.Sort(expSortCol, ListSortDirection.Descending);
            //                break;
            //            }
            //        default:
            //            break;
            //    }
            //}
            //if (expPosition > -1)
            //    experimentViewBindingSource.Position = expPosition;


        }

        //TODO: Freshweights should be refreshed if navigated back from btach control

        #region BINDING
        private void BindMaterial()
        {
            var empty = from x in new List<MaterialView> { new MaterialView { UId = Guid.Empty, Name = "none" } } select x;
            var q = from x in _dataContext.MaterialViews orderby x.Name select x;
            materialBindingSource.DataSource = empty.Union(q);
        }

        private void BindExperiment()
        {
            var q = from x in _dataContext.ExperimentViews
                    where x.Id != "EB"
                    where x.Id != "?"
                    orderby x.Id
                    select x;
            experimentViewBindingSource.DataSource = q;
        }

        private void experimentViewBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            try
            {
                BindFreshweights();
            }
            catch (Exception ex)
            {
                Microsoft.SqlServer.MessageBox.ExceptionMessageBox box = new Microsoft.SqlServer.MessageBox.ExceptionMessageBox(ex);
                box.Show(this);
            }
        }

        private EnzymeDBDataContext _currentFreshWeigthViewContext;
        private bool _invalidateFreshWeigthViewContext = true;
        private void BindFreshweights()
        {
            try
            {
                if (_invalidateFreshWeigthViewContext)
                {
                    if (_currentFreshWeigthViewContext != null)
                    {
                        _currentFreshWeigthViewContext.Dispose();
                        _currentFreshWeigthViewContext = null;
                    }
                    _currentFreshWeigthViewContext = _surface.GetDataContext();
                    _invalidateFreshWeigthViewContext = false;
                }
            }
            catch (Exception e)
            {
                Microsoft.SqlServer.MessageBox.ExceptionMessageBox box = new Microsoft.SqlServer.MessageBox.ExceptionMessageBox(e);
                box.Show(this);
            }

            ExperimentView ev = experimentViewBindingSource.Current as ExperimentView;
            if (ev != null)
            {
                var q = from x in _currentFreshWeigthViewContext.FreshWeightViews
                        where x.ExperimentUId == ev.UId
                        orderby x.Sample
                        orderby x.Aliquot
                        select x;

                freshWeightViewBindingSource.DataSource = q;
            }
            else
                freshWeightViewBindingSource.DataSource = null;

        }


        #endregion

        #region CRUD Experiment
        private Guid _newItemUId = new Guid("11111111-1111-1111-1111-111111111111");

        //toolbar initiated add-action
        private void experimentAddNewItem_Click(object sender, EventArgs e)
        {
            if (!experimentDataGridView.IsCurrentCellInEditMode)
            {
                experimentViewBindingSource.AddNew();
                experimentDataGridView.BeginEdit(true);
            }
        }

        //create a default experiment for adding
        private void experimentViewBindingSource_AddingNew(object sender, AddingNewEventArgs e)
        {
            e.NewObject = new ExperimentView { UId = _newItemUId, Id = "NewExperiment", Material_Fk = null };
        }

        //validate added or updated material data
        private void experimentDataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (experimentDataGridView.IsCurrentCellInEditMode)
            {
                var mv = experimentDataGridView.Rows[e.RowIndex].DataBoundItem as ExperimentView;
                if (mv == null)
                {
                    return;
                }
                if (experimentDataGridView.Columns[e.ColumnIndex].DataPropertyName == "Id")
                {
                    if (string.IsNullOrEmpty(e.FormattedValue.ToString()))
                    {
                        experimentDataGridView.Rows[e.RowIndex].ErrorText = "The Experiment ID can't be empty.";
                        e.Cancel = true;
                    }
                    else
                    {
                        var check = _dataContext.ExperimentViews.SingleOrDefault(x => x.UId != mv.UId && x.Id.ToLower() == e.FormattedValue.ToString().ToLower().Trim());
                        if (check != null)
                        {
                            experimentDataGridView.Rows[e.RowIndex].ErrorText = "Experiment with this name already exist.";
                            e.Cancel = true;
                        }
                    }
                }
            }
        }

        //save added and updated experiment
        private void experimentDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            experimentDataGridView.Rows[e.RowIndex].ErrorText = null;

            ExperimentView mv = null;
            try
            {
                mv = experimentDataGridView.Rows[e.RowIndex].DataBoundItem as ExperimentView;
            }
            catch (IndexOutOfRangeException)
            {
                //handles case where new row is edited and then escape key is pressed to cancel the new row
            }

            if (mv != null)
            {
                if (mv.UId == _newItemUId)
                {
                    mv.UId = _surface.AddExperiment(mv.Id, mv.Material_Fk);
                }
                else
                {
                    _surface.UpdateExperiment(mv.UId, mv.Id, mv.Material_Fk);
                }
            }
        }

        //toolbar initiated delete-action
        private void experimentDeleteItem_Click(object sender, EventArgs e)
        {
            if (ConfirmExperimentDelete())
            {
                ExperimentView mv = experimentViewBindingSource.Current as ExperimentView;
                if (mv != null)
                {
                    _surface.DeleteExperiment(mv.UId);
                    experimentViewBindingSource.RemoveCurrent();
                }
            }
        }

        //gridview initiated delete-action
        private void experimentDataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            e.Cancel = !ConfirmExperimentDelete();
        }

        //delete experiment 
        private void experimentDataGridView_UserDeletedRow(object sender, DataGridViewRowEventArgs e)
        {
            var mv = e.Row.DataBoundItem as ExperimentView;
            if (mv != null)
            {
                _surface.DeleteExperiment(mv.UId);
            }
        }

        //request user confirmation for delete
        private bool ConfirmExperimentDelete()
        {
            return MessageBox.Show("Are you sure you want to delete the current experiment and all related fresh weights?", "Confirm experiment delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                == DialogResult.Yes;
        }
        #endregion

        #region CRUD FreshWeight
        //toolbar initiated add-action
        private void freshweightAddItem_Click(object sender, EventArgs e)
        {
            if (!freshWeightDataGridView.IsCurrentCellInEditMode)
            {
                freshWeightViewBindingSource.AddNew();
                freshWeightDataGridView.BeginEdit(true);
            }
        }

        //create a default freshweight for adding
        private void freshWeightViewBindingSource_AddingNew(object sender, AddingNewEventArgs e)
        {
            ExperimentView ev = experimentViewBindingSource.Current as ExperimentView;
            if (ev != null)
            {
                int nextSampleId = 1;
                while (_dataContext.FreshWeightViews.FirstOrDefault(x => x.ExperimentUId == ev.UId && x.Sample == nextSampleId) != null)
                {
                    nextSampleId++;
                }
                e.NewObject = new FreshWeightView { UId = _newItemUId, ExperimentUId = ev.UId, Material_Fk = ev.Material_Fk, ExperimentId = ev.Id, Sample = nextSampleId, Aliquot = 1, Value = 0, State = "free" };
            }
        }

        //validate added or updated freshweight data
        private void freshWeightDataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (freshWeightDataGridView.IsCurrentCellInEditMode)
            {
                var mv = freshWeightDataGridView.Rows[e.RowIndex].DataBoundItem as FreshWeightView;
                if (mv == null)
                {
                    return;
                }
                if (freshWeightDataGridView.Columns[e.ColumnIndex].DataPropertyName == "Sample" || freshWeightDataGridView.Columns[e.ColumnIndex].DataPropertyName == "Aliquot")
                {
                    var exp = experimentViewBindingSource.Current as ExperimentView;
                    int intVal;
                    string val = e.FormattedValue.ToString();
                    if (!int.TryParse(val, out intVal))
                    {
                        freshWeightDataGridView.Rows[e.RowIndex].ErrorText = "The value is not a valid integer number.";
                        e.Cancel = true;
                    }
                    else
                    {
                        if (freshWeightDataGridView.Columns[e.ColumnIndex].DataPropertyName == "Sample")
                        {
                            var check = _dataContext.FreshWeightViews.SingleOrDefault(x => x.UId != mv.UId && x.ExperimentUId == exp.UId && x.Aliquot == mv.Aliquot && x.Sample == intVal);
                            if (check != null)
                            {
                                freshWeightDataGridView.Rows[e.RowIndex].ErrorText = "An aliqout with this sample id already exist.";
                                e.Cancel = true;
                            }
                        }
                        if (freshWeightDataGridView.Columns[e.ColumnIndex].DataPropertyName == "Aliquot")
                        {
                            var check = _dataContext.FreshWeightViews.SingleOrDefault(x => x.UId != mv.UId && x.ExperimentUId == exp.UId && x.Sample == mv.Sample && x.Aliquot == intVal);
                            if (check != null)
                            {
                                freshWeightDataGridView.Rows[e.RowIndex].ErrorText = "An sample with this aliqout id already exist.";
                                e.Cancel = true;
                            }
                        }
                    }
                }
                if (freshWeightDataGridView.Columns[e.ColumnIndex].DataPropertyName == "Value")
                {
                    double test;
                    string val = e.FormattedValue.ToString();
                    if (!double.TryParse(val, out test))
                    {
                        freshWeightDataGridView.Rows[e.RowIndex].ErrorText = "The value is not a valid floating number.";
                        e.Cancel = true;
                    }
                }
            }
        }

        //save added and updated freshweights
        private void freshWeightDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            var exp = experimentViewBindingSource.Current as ExperimentView;
            freshWeightDataGridView.Rows[e.RowIndex].ErrorText = null;

            FreshWeightView fwv = null;
            try
            {
                fwv = freshWeightDataGridView.Rows[e.RowIndex].DataBoundItem as FreshWeightView;
            }
            catch (IndexOutOfRangeException)
            {
                //handles case where new row is edited and then escape key is pressed to cancel the new row
            }

            if (fwv != null)
            {
                if (fwv.UId == _newItemUId)
                {
                    fwv.UId = _surface.AddFreshweight(fwv.ExperimentId, fwv.Sample, fwv.Aliquot, fwv.Value);
                }
                else
                {
                    _surface.UpdateFreshweight(fwv.UId, fwv.ExperimentId, fwv.Sample, fwv.Aliquot, fwv.Value);
                }
            }
        }

        //toolbar initiated delete-action
        private void freshweightDeleteItem_Click(object sender, EventArgs e)
        {
            if (ConfirmFreshWeightDelete())
            {
                foreach (DataGridViewRow item in freshWeightDataGridView.SelectedRows)
                {
                    FreshWeightView fwv = item.DataBoundItem as FreshWeightView;
                    if (fwv != null)
                    {
                        _surface.DeleteFreshweight(fwv.UId);
                        freshWeightViewBindingSource.Remove(fwv);
                    }
                }

            }
        }

        //gridview initiated delete-action
        private void freshWeightDataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            e.Cancel = !ConfirmFreshWeightDelete();
        }

        //delete freshweight 
        private void freshWeightDataGridView_UserDeletedRow(object sender, DataGridViewRowEventArgs e)
        {
            var fwv = e.Row.DataBoundItem as FreshWeightView;
            if (fwv != null)
            {
                _surface.DeleteFreshweight(fwv.UId);
            }
        }

        //request user confirmation for delete
        private bool ConfirmFreshWeightDelete()
        {
            return MessageBox.Show("Are you sure you want to delete the current freshweight?\r\nThis action will also delete parts of batchlayouts and all corresponding raw data!\r\nThis action can also result in invalid batches!", "Confirm freshweight delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                == DialogResult.Yes;
        }

        //paste freshweights from clipboard
        private void OnPasteFreshWeights(object sender, EventArgs e)
        {
            if (Clipboard.ContainsText())
            {
                var exp = experimentViewBindingSource.Current as ExperimentView;
                string rawText = Clipboard.GetText();
                string[] lines = rawText.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                foreach (string line in lines)
                {
                    string[] fWeightDef = line.Split("\t".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    int sample;
                    int aliquot;
                    double weight;
                    if (fWeightDef.Length > 2
                        && int.TryParse(fWeightDef[0], out sample)
                        && int.TryParse(fWeightDef[1], out aliquot)
                        && double.TryParse(fWeightDef[2], out weight))
                    {
                        if (fWeightDef.Length > 3)
                            _surface.AddOrUpdateFreshweight(exp.Id, sample, aliquot, weight, fWeightDef[3].Trim());
                        else
                            _surface.AddOrUpdateFreshweight(exp.Id, sample, aliquot, weight);
                        var fwv = _dataContext.FreshWeightViews.Single(x => x.ExperimentUId == exp.UId
                                                                    && x.Sample == sample
                                                                    && x.Aliquot == aliquot);
                        fwv.Value = weight;
                    }
                }
                BindFreshweights();
            }
        }

        #endregion

        #region Formatting

        void experimentDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.Value != null)
            {

                if (e.ColumnIndex == 1)
                {
                    if (((string)e.Value).Equals("none"))
                    {
                        e.CellStyle.Font = new Font(e.CellStyle.Font, FontStyle.Italic);
                        e.CellStyle.ForeColor = Color.Silver;
                    }
                    else
                    {
                        e.CellStyle.Font = new Font(e.CellStyle.Font, FontStyle.Regular);
                        e.CellStyle.ForeColor = Color.Black;
                    }
                }
            }
        }

        void freshWeightsDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.Value != null && e.Value != DBNull.Value)
            {

                if (freshWeightDataGridView.Columns[e.ColumnIndex].DataPropertyName.Equals("State"))
                {

                    if (((string)e.Value).Equals("in use"))
                    {
                        //e.CellStyle.Font = new Font(e.CellStyle.Font, FontStyle.Bold);
                        e.CellStyle.ForeColor = Color.Red;
                    }
                    else
                    {
                        e.CellStyle.ForeColor = Color.Green;
                    }
                }
            }

        }


        #endregion

        private void ApplyExperimentSecurity()
        {
            experimentDataGridView.AllowUserToDeleteRows = false;
            experimentDataGridView.ReadOnly = true;
            experimentViewBindingSource.AllowNew = false;
            experimentDeleteItem.Enabled = false;

            if (_surface.SecDescriptor.Rights.ContainsKey("Experiments"))
            {
                foreach (TableRight tr in _surface.SecDescriptor.Rights["Experiments"])
                {
                    switch (tr)
                    {
                        case TableRight.Insert:
                        {
                            experimentViewBindingSource.AllowNew = true;
                            break;
                        }
                        case TableRight.Delete:
                        {
                            experimentDataGridView.AllowUserToDeleteRows = true;
                            experimentDeleteItem.Enabled = true;
                            break;
                        }
                        case TableRight.Update:
                        {
                            experimentDataGridView.ReadOnly = false;
                            break;
                        }
                    }
                }
            }
        }

        private void ApplyFreshWeightSecurity()
        {
            freshWeightDataGridView.AllowUserToDeleteRows = false;
            freshWeightDataGridView.ReadOnly = true;
            freshWeightViewBindingSource.AllowNew = false;
            freshWeightPasteStripButton.Enabled = false;
            freshweightDeleteItem.Enabled = false;

            if (_surface.SecDescriptor.Rights.ContainsKey("FreshWeights"))
            {
                foreach (TableRight tr in _surface.SecDescriptor.Rights["FreshWeights"])
                {
                    switch (tr)
                    {
                        case TableRight.Insert:
                        {
                            freshWeightViewBindingSource.AllowNew = true;
                            freshWeightPasteStripButton.Enabled = true;
                            break;
                        }
                        case TableRight.Delete:
                        {
                            freshWeightDataGridView.AllowUserToDeleteRows = true;
                            freshweightDeleteItem.Enabled = true;
                            break;
                        }
                        case TableRight.Update:
                        {
                            freshWeightDataGridView.ReadOnly = false;
                            break;
                        }
                    }
                }
            }

            StateColumn.ReadOnly = true; //is always readonly
        }
    }
}
